// Copyright (c) 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_TEST_DWRITE_FONT_FAKE_SENDER_WIN_H_
#define CONTENT_TEST_DWRITE_FONT_FAKE_SENDER_WIN_H_

#include <stddef.h>
#include <stdint.h>
#include <wrl.h>

#include <memory>
#include <utility>
#include <vector>

#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/strings/string16.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_platform_file.h"
#include "ipc/ipc_sender.h"

struct DWriteFontStyle;
struct MapCharactersResult;

namespace content {

class FakeFontCollection;

// Creates a new FakeFontCollection, seeded with some basic data, and returns a
// Sender that can be used to interact with the collection.
IPC::Sender* CreateFakeCollectionSender();

// Helper class for describing a font object. Use FakeFontCollection instead.
class FakeFont {
public:
    explicit FakeFont(const base::string16& name);

    FakeFont(const FakeFont& other);

    ~FakeFont();

    FakeFont& AddFilePath(const base::string16& file_path)
    {
        file_paths_.push_back(file_path);
        return *this;
    }

    FakeFont& AddFileHandle(IPC::PlatformFileForTransit handle)
    {
        file_handles_.push_back(handle);
        return *this;
    }

    FakeFont& AddFamilyName(const base::string16& locale,
        const base::string16& family_name)
    {
        family_names_.emplace_back(locale, family_name);
        return *this;
    }

    const base::string16& font_name() { return font_name_; }

private:
    friend FakeFontCollection;
    base::string16 font_name_;
    std::vector<base::string16> file_paths_;
    std::vector<IPC::PlatformFileForTransit> file_handles_;
    std::vector<std::pair<base::string16, base::string16>> family_names_;

    DISALLOW_ASSIGN(FakeFont);
};

// Implements a font collection that supports interaction through sending IPC
// messages from dwrite_font_proxy_messages.h.
// Usage:
//   Create a new FakeFontCollection.
//   Call AddFont() to add fonts.
//     For each font, call methods on the font to configure the font.
//     Note: the indices of the fonts will correspond to the order they were
//         added. The collection will not sort or reorder fonts in any way.
//   Call GetSender()/GetTrackingSender() to obtain an IPC::Sender.
//   Call Send() with DWriteFontProxyMsg_* to interact with the collection.
//   Call MessageCount()/GetMessage() to inspect the messages that were sent.
//
// The internal code flow for GetSender()/Send() is as follows:
//   GetSender() returns a new FakeSender, pointing back to the collection.
//   FakeSender::Send() will create a new ReplySender and call
//       ReplySender::OnMessageReceived()
//   ReplySender::OnMessageReceived() contains the message map, which will
//       internally call ReplySender::On*() and ReplySender::Send()
//   ReplySender::Send() will save the reply message, to be used later.
//   FakeSender::Send() will retrieve the reply message and save the output.
class FakeFontCollection : public base::RefCounted<FakeFontCollection> {
public:
    FakeFontCollection();

    FakeFont& AddFont(const base::string16& font_name);

    size_t MessageCount();

    IPC::Message* GetMessage(size_t index);

    IPC::Sender* GetSender();

    // Like GetSender(), but will keep track of all sent messages for inspection.
    IPC::Sender* GetTrackingSender();

protected:
    // This class handles sending the reply message back to the "renderer"
    class ReplySender : public IPC::Sender {
    public:
        explicit ReplySender(FakeFontCollection* collection);

        ~ReplySender() override;

        std::unique_ptr<IPC::Message>& OnMessageReceived(const IPC::Message& msg);

        bool Send(IPC::Message* msg) override;

    private:
        void OnFindFamily(const base::string16& family_name, uint32_t* index);

        void OnGetFamilyCount(uint32_t* count);

        void OnGetFamilyNames(
            uint32_t family_index,
            std::vector<std::pair<base::string16, base::string16>>* family_names);
        void OnGetFontFiles(uint32_t family_index,
            std::vector<base::string16>* file_paths,
            std::vector<IPC::PlatformFileForTransit>* file_handles);

        void OnMapCharacters(const base::string16& text,
            const DWriteFontStyle& font_style,
            const base::string16& locale_name,
            uint32_t reading_direction,
            const base::string16& base_family_name,
            MapCharactersResult* result);

    private:
        scoped_refptr<FakeFontCollection> collection_;
        std::unique_ptr<IPC::Message> reply_;

        DISALLOW_COPY_AND_ASSIGN(ReplySender);
    };

    // This class can be used by the "renderer" to send messages to the "browser"
    class FakeSender : public IPC::Sender {
    public:
        FakeSender(FakeFontCollection* collection, bool track_messages);

        ~FakeSender() override;

        bool Send(IPC::Message* message) override;

    private:
        bool track_messages_;
        scoped_refptr<FakeFontCollection> collection_;

        DISALLOW_COPY_AND_ASSIGN(FakeSender);
    };

    void OnFindFamily(const base::string16& family_name, uint32_t* index);

    void OnGetFamilyCount(uint32_t* count);

    void OnGetFamilyNames(
        uint32_t family_index,
        std::vector<std::pair<base::string16, base::string16>>* family_names);

    void OnGetFontFiles(uint32_t family_index,
        std::vector<base::string16>* file_paths,
        std::vector<IPC::PlatformFileForTransit>* file_handles);

    void OnMapCharacters(const base::string16& text,
        const DWriteFontStyle& font_style,
        const base::string16& locale_name,
        uint32_t reading_direction,
        const base::string16& base_family_name,
        MapCharactersResult* result);

    std::unique_ptr<ReplySender> GetReplySender();

private:
    friend class base::RefCounted<FakeFontCollection>;
    ~FakeFontCollection();

    std::vector<FakeFont> fonts_;
    std::vector<std::unique_ptr<IPC::Message>> messages_;

    DISALLOW_COPY_AND_ASSIGN(FakeFontCollection);
};

} // namespace content

#endif // CONTENT_TEST_DWRITE_FONT_FAKE_SENDER_WIN_H_
